define(['jquery','jquerymobile','require'],function($, jqm, require) {
    console.log("utils loaded");
    
    var accessTokenName = "Access-Token";
    var accessTokenValue = "";
    var userName = "";
    var userPassword = "";
    var piServerUrl = "";
    var fileSaveLocation = "";
    var contactsFieldMap= {};
    /**
     * sleep for several millisecond
     * @param time specified time to "stop" the current task, in millisecond
     */
    var sleep = function(time) {
        if (typeof time != 'number')
            return;

        for(var t = Date.now();Date.now() - t <= time;);
    };
    
    /**
     * Show native toast messages, only available on phonegap environment, otherwise, the method will use `alert`
     * as a fallback
     * @param {String} message The message to be shown
     * @param {String} duration The duration of toast shown, available values are 'short' and 'long'
     * @param {String} position The position of toast shown, available values are 'top', 'center' and 'bottom'
     */
    var showToast = function(message, duration, position) {
        if (window.isCordovaApp) {
            try {
                window.plugins.toast.show(message, duration, position);
            } catch (err) {
                alert("Error while showing toast: " + err);
            }
        }
        else
            alert(message);
    }

    if (window.isCordovaApp) {
        contactsFieldMap = {
            "displayName" : navigator.contacts.fieldType.displayName,
            "name": navigator.contacts.fieldType.name,
        };
    }

    return {
        navigateTo: function(url) {
            $(':mobile-pagecontainer').pagecontainer("change", url);
        },

        defaultBackendHandler: function() {
            showToast("Failed to fetch data, please check your network availability.");
        },

        showLoader: function() {
            $.mobile.loading( "show" );
        },

        hideLoader: function() {
            $.mobile.loading( "hide" );
        },

        getCurrentDate: function() {
            var today = new Date();
            var dd = today.getDate();
            var mm = today.getMonth() + 1;
            var yyyy = today.getFullYear();

            if (dd < 10) {
                dd = '0' + dd;
            }

            if (mm < 10) {
                mm = '0' + mm;
            }

            today = yyyy + '-' + mm + '-' + dd;

            return today;
        },

        parseTo24HourFormat: function(rawDateStr) {
            var parts; 
            var period;
            var hour;
            var min;

            try {
                parts = rawDateStr.split(" ");
                period = parts[1];
                hour = parts[0].split(":")[0];
                min = parts[0].split(":")[1];
            } catch (err) {
                console.log('Parse Time Format Failed! The rawDateStr is ' + rawDateStr);
                return '';
            }

            if (period === 'PM')
                hour = parseInt(hour) + 12;
            
            return hour + ':' + min;
        },

        extractTimeFromDatetime: function(rawDatetimeStr) {
            var date;

            try {
                date = rawDatetimeStr.split(" ")[1];
            } catch (err) {
                console.log("Extract date failed on rawDatetimeStr: " + rawDatetimeStr + "\n" + err.message);
                date = '';
            }

            return date;
        },

        extractItemOnPathFromLast: function(path, n) {
            var filename = '';

            try {
                var nameList = path.split("/");
                filename = nameList[nameList.length - n];
            } catch (err) {
                console.log("Error to extract filename from path: " + path + "\n" + err.message);
            }

            return filename;
        },

        extractUpDirPath: function(path) {
            var upPath = '';

            try {
                var nameList = path.split("/");

                nameList.pop();
                upPath = nameList.join("/");
            } catch (err) {
                console.log("Error to extract up dir from path: " + path + "\n" + err.message);
            }

            return upPath;
        },

        downloadFile: function(url, dest, successCallback, errorCallback) {
            if (!window.isCordovaApp) {
                console.log("Phonegap only feature. Aborted.");
                return;
            }

            window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
                try {
                    var fileTransfer = new FileTransfer();
                    var headers = {};

                    headers[accessTokenName] = accessTokenValue;

                    fileTransfer.download(
                        encodeURI(url),
                        fileSystem.root.toURL() + '/' + fileSaveLocation + "/" + dest,
                        function (entry) {
                            successCallback(entry);
                        },
                        function(error) {
                            errorCallback(error);
                        },
                        true,
                        {
                            headers: headers,
                        }
                    );
                } catch (err) {
                    alert("Error while downloaing: " + err.message);
                }
            });
        },

        uploadFile: function(url, reqParamsMap, mediaType, uploadSuccessCallback, uploadFailCallback) {
            if (!window.isCordovaApp) {
                console.log("Phonegap only feature. Aborted.");
                return;
            }

            var ft;
            var source = navigator.camera.PictureSourceType.PHOTOLIBRARY;
            var mediaTypeMap = {
                picture: navigator.camera.MediaType.PICTURE,
                video: navigator.camera.MediaType.VIDEO,
                allmedia: navigator.camera.MediaType.ALLMEDIA,
            };

            // Local file path
            var destinationType = navigator.camera.DestinationType.FILE_URI;

            // Set media type, which is the file type we hope to choose
            var mediaType = mediaTypeMap[mediaType];

            if (undefined === mediaType) {
                console.error("Unsupported file type: " + mediaType);
                return;
            }

            var options = {
                quality: 50,
                destinationType : destinationType,
                sourceType : source,
                mediaType : mediaType
            };

            // Start select file
            navigator.camera.getPicture(
                                function(fileURI) {
                                    var options = new FileUploadOptions();
                                    options.fileKey = "file";
                                    options.fileName = fileURI.substr(fileURI.lastIndexOf('/') + 1);
                                    options.mimeType = "multipart/form-data";
                                    options.chunkedMode = false;

                                    ft = new FileTransfer();

                                    var params = reqParamsMap;

                                    var headers = {};
                                    headers[accessTokenName] = accessTokenValue,
                                    headers["Connection"] = "close";
                                            
                                    
                                    options.headers = headers;
                                    options.params = params;

                                    var uploadURL = encodeURI(url);
                                    try {
                                        $.mobile.loading( "show" );
                                        ft.upload(
                                                    fileURI, 
                                                    uploadURL, 
                                                    uploadSuccessCallback, 
                                                    uploadFailCallback, 
                                                    options, true
                                                  );
                                    } catch (err) {
                                        alert("Error when uploading: " + err);
                                        $.mobile.loading( "hide" );
                                    }

                                },
                                function(message) {
                                    showToast("No file selected.");
                                },
                                options); 
        },

        searchContacts: function(filterKey, searchFields, callback) {
            if (!window.isCordovaApp) {
                console.log("Phonegap only feature. Aborted.");
                return;
            }

            var searchKey = (undefined === filterKey) ? "" : filterKey;
            var searchFieldList = (undefined === searchFields) ? ['displayName'] : searchFields;
            var options = new ContactFindOptions();
            var fields = [];
            var onSuccess = function(contacts) {
                callback(contacts);
            };
            var onError = function(contactError) {
                alert('Failed to get contacts: ' + contactError);
            };

            options.filter = searchKey;
            options.multiple = true;
            
            searchFieldList.forEach(function(element, index, array) {
                if (element in contactsFieldMap)
                    fields.push(contactsFieldMap[element]);
            });
            
            try {
                navigator.contacts.find(fields, onSuccess, onError, options);
            } catch (err) {
                alert("Failed to get contacts: " + err);
            }
        },

        syncContacts: function syncContacts(contactsList, callback) {
            if (0 === contactsList.length) {
                callback();
                return;
            }

            var element = contactsList.shift();
            element.save(
                            function(contact) {
                                sleep(1000);
                                syncContacts(contactsList, callback);
                            },
                            function(err) {
                                alert("Error when saving contact: " + err.code);
                            }
                        );
        },

        produceShortString: function(raw, max) {
            var max;
            var result = raw;
            
            try {
                max = parseInt(max);
                if (raw.length > max) 
                    result = raw.substring(0, max - 3) + "...";
            } catch (err) {
                console.log("Error when producing short string: " + err.message);
            }
            
            return result;    
        },

        isStrEmpty: function(str) {
            if (undefined === str || null === str)
                return true;
            
            return str.trim().length === 0 ? true : false;
        },

        isObjEmpty: function(obj) {
            if (undefined === obj || null === obj)
                return true;
            
            return false;
        },

        ifNull: function(raw, replacement) {
            return (raw === undefined || raw === null) ? replacement : raw;
        },
        
        exitApp: function() {
            navigator.app.exitApp();
        },    
        
        getCurrentLocation: function(successCallback, errorCallback, timeout, isLivingInChina) {
            var onError = errorCallback;
            var onSuccess = successCallback; 
            var options = {
                  enableHighAccuracy: true,
                  timeout: timeout,
                  maximumAge: 3000
            };

            try {
                // Due to Chinese complex Internet environment, Google Geolocation service is always unavailable, so
                // we have to use Baidu Map Geolocation service as a fallback for users in China.
                if (isLivingInChina)
                    window.BaiduGeolocation.getCurrentPosition(onSuccess, onError);
                else
                    navigator.geolocation.getCurrentPosition(onSuccess, onError, options);
            } catch (err) {
                ("Error: " + err);
            }
        },    

        sendAppToBackground: function(successCallback, errorCallback) {
            try {
                window.BackHome.goHome(successCallback, errorCallback);
            } catch (err) {
                alert("Error: " + err);
            }
        },

        sendNotify: function(title, text, ticker, enableExtraEffects, successCallback, errorCallback) {
            try {
                window.StatusBarNotification.sendNotify(title, text, ticker, enableExtraEffects, successCallback, errorCallback);
            } catch (err) {
                alert("Error: " + err);
            }
        },

        showToast: showToast,

        getKeyByValueFromObject: function(hash, value) {
            if (hash === null || hash === undefined)
                return null;

            var key = null;

            for (var k in hash) {
                if (hash[k] === value) {
                    key = k;
                    break;
                }
            }

            return key;
        },

        appConfig: function() {

            return {
                serverHost: function (url) {
                    if (null === url || undefined === url)
                        return piServerUrl;

                    piServerUrl = window.isCordovaApp ? url : '';    
                },
                projectName: "sweet_home",
                accessTokenName: function (name) {
                    if (null === name || undefined === name)
                        return accessTokenName;
                    
                    accessTokenName = name;
                },
                accessTokenValue: function (value) {
                    if (null === value || undefined === value)
                        return accessTokenValue;
                    
                    accessTokenValue = value;
                },
                fileSaveLocation: function (loc) {
                    if (null === loc || undefined === loc)
                        return fileSaveLocation;
                    
                    fileSaveLocation = loc;
                },
                userName: function(name) {
                    if (null === name || undefined === name)
                        return userName;
                    
                    userName = name;
                },
                userPassword: function(passwd) {
                    if (null === passwd || undefined === passwd)
                        return userPassword;
                    
                    userPassword = passwd;
                },
            };
        },
    };
});
